﻿// Decompiled with JetBrains decompiler
// Type: UnityEngine.UnitySynchronizationContext
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E6AE6B5A-2752-4B07-9528-C8B77C62CE79
// Assembly location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
// XML documentation location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.xml

using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using UnityEngine.Scripting;

#nullable disable
namespace UnityEngine
{
  internal sealed class UnitySynchronizationContext : SynchronizationContext
  {
    private const int kAwqInitialCapacity = 20;
    private readonly List<UnitySynchronizationContext.WorkRequest> m_AsyncWorkQueue;
    private readonly List<UnitySynchronizationContext.WorkRequest> m_CurrentFrameWork = new List<UnitySynchronizationContext.WorkRequest>(20);
    private readonly int m_MainThreadID;
    private int m_TrackedCount = 0;

    private UnitySynchronizationContext(int mainThreadID)
    {
      this.m_AsyncWorkQueue = new List<UnitySynchronizationContext.WorkRequest>(20);
      this.m_MainThreadID = mainThreadID;
    }

    private UnitySynchronizationContext(
      List<UnitySynchronizationContext.WorkRequest> queue,
      int mainThreadID)
    {
      this.m_AsyncWorkQueue = queue;
      this.m_MainThreadID = mainThreadID;
    }

    public override void Send(SendOrPostCallback callback, object state)
    {
      if (this.m_MainThreadID == Thread.CurrentThread.ManagedThreadId)
      {
        callback(state);
      }
      else
      {
        using (ManualResetEvent waitHandle = new ManualResetEvent(false))
        {
          lock (this.m_AsyncWorkQueue)
            this.m_AsyncWorkQueue.Add(new UnitySynchronizationContext.WorkRequest(callback, state, waitHandle));
          waitHandle.WaitOne();
        }
      }
    }

    public override void OperationStarted() => Interlocked.Increment(ref this.m_TrackedCount);

    public override void OperationCompleted() => Interlocked.Decrement(ref this.m_TrackedCount);

    public override void Post(SendOrPostCallback callback, object state)
    {
      lock (this.m_AsyncWorkQueue)
        this.m_AsyncWorkQueue.Add(new UnitySynchronizationContext.WorkRequest(callback, state));
    }

    public override SynchronizationContext CreateCopy()
    {
      return (SynchronizationContext) new UnitySynchronizationContext(this.m_AsyncWorkQueue, this.m_MainThreadID);
    }

    private void Exec()
    {
      lock (this.m_AsyncWorkQueue)
      {
        this.m_CurrentFrameWork.AddRange((IEnumerable<UnitySynchronizationContext.WorkRequest>) this.m_AsyncWorkQueue);
        this.m_AsyncWorkQueue.Clear();
      }
      while (this.m_CurrentFrameWork.Count > 0)
      {
        UnitySynchronizationContext.WorkRequest workRequest = this.m_CurrentFrameWork[0];
        this.m_CurrentFrameWork.RemoveAt(0);
        workRequest.Invoke();
      }
    }

    private bool HasPendingTasks() => this.m_AsyncWorkQueue.Count != 0 || this.m_TrackedCount != 0;

    [RequiredByNativeCode]
    private static void InitializeSynchronizationContext()
    {
      SynchronizationContext.SetSynchronizationContext((SynchronizationContext) new UnitySynchronizationContext(Thread.CurrentThread.ManagedThreadId));
    }

    [RequiredByNativeCode]
    private static void ExecuteTasks()
    {
      if (!(SynchronizationContext.Current is UnitySynchronizationContext current))
        return;
      current.Exec();
    }

    [RequiredByNativeCode]
    private static bool ExecutePendingTasks(long millisecondsTimeout)
    {
      if (!(SynchronizationContext.Current is UnitySynchronizationContext current))
        return true;
      Stopwatch stopwatch = new Stopwatch();
      stopwatch.Start();
      while (current.HasPendingTasks() && stopwatch.ElapsedMilliseconds <= millisecondsTimeout)
      {
        current.Exec();
        Thread.Sleep(1);
      }
      return !current.HasPendingTasks();
    }

    private struct WorkRequest(
      SendOrPostCallback callback,
      object state,
      ManualResetEvent waitHandle = null)
    {
      private readonly SendOrPostCallback m_DelagateCallback = callback;
      private readonly object m_DelagateState = state;
      private readonly ManualResetEvent m_WaitHandle = waitHandle;

      public void Invoke()
      {
        try
        {
          this.m_DelagateCallback(this.m_DelagateState);
        }
        finally
        {
          this.m_WaitHandle?.Set();
        }
      }
    }
  }
}
